/* Copyright(C): Leaf Johnson 2009,2010

    This file is part of leaf-lib.

    leaf-lib is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    leaf-lib is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with leaf-lib.  If not, see <http://www.gnu.org/licenses/>.


 * 
 * 
 */


#include <devices_ext/lcd.h>
#include <util/delay.h>
#include <leaf/base.h>

#define LCD_DELAY_INIT 15
#define LCD_DELAY_DATA 40
#define LCD_DELAY_EN   10
static void lcdWriteEn();

/*LCD 发送数据的函数，根据不同的连接执行不同的动作*/
void lcd_trans(uint8_t data){
#if (LCD_CONN_TYPE == LCD_CONNTYPE_L4)
		uint8_t half;
		half = data >> 4;            //get higher 4 bits
		LCD_DATA_PORT &= 0xf0;       //clear 4-bits send port
		LCD_DATA_PORT |= half;       //send higher 4-bits
		lcdWriteEn();
		half = data & 0x0f;          //get lower 4 bits
		LCD_DATA_PORT &= 0xf0;       //clear 4-bits send port
		LCD_DATA_PORT |= half;       //send lower 4-bits
		lcdWriteEn();
#elif (LCD_CONN_TYPE == LCD_CONNTYPE_H4)
		uint8_t half;
		half = data & 0xf0;          //get higher half
		LCD_DATA_PORT &= 0x0f;       //clear 4-bits send port
		LCD_DATA_PORT |= half;       //send higher half
		lcdWriteEn();
		half = data << 4;            //get lower half
		LCD_DATA_PORT &= 0x0f;       //clear 4-bits send port
		LCD_DATA_PORT |= half;       //send lower half
		lcdWriteEn();
#elif( LCD_CONN_TYPE == LCD_CONNTYPE_8 )
		LCD_DATA_PORT = data;
		lcdWriteEn();
#endif
}

/*初始化，液晶寝化时要发一串串的指令*/
void lcd_init(void)         //Һ����ʼ��
{
	unsigned char i;
	LCD_DATA_DDR |= LCD_DATA_MASK;
	LCD_EN_DDR|=LCD_EN;       //����EN����Ϊ���
	LCD_RS_DDR|=LCD_RS;       //����RS����Ϊ���
#if( LCD_CONN_TYPE == LCD_CONNTYPE_8 )
		lcd_command(0x38);
		lcdWriteEn();
		_delay_us(LCD_DELAY_INIT);
		lcd_command(0x38);
#else
		lcd_command(0x28);
		lcdWriteEn();
		_delay_us(LCD_DELAY_INIT);
		lcd_command(0x28);
#endif
	for (i=0;i<20;i++)
	{
#if ( LCD_CONN_TYPE == LCD_CONNTYPE_8 )
			lcd_posc(0,0,0x38); //4bit test
#else
			lcd_posc(0,0,0x28); //4bit test
#endif
		_delay_ms(LCD_DELAY_INIT);
	}
	lcd_command(0x0c);  //显示开
	lcd_command(0x01);  //清屏
	_delay_ms(LCD_DELAY_INIT);
}

/*在LCD的EN脚上产生一个下降沿*/
static void lcdWriteEn(void)
{
	LCD_EN_PORT|=LCD_EN;
	_delay_us(LCD_DELAY_EN);
	LCD_EN_PORT&=~LCD_EN;
}

/*向lcd发个指令*/
void lcd_command(unsigned char command)
{
	_delay_us(LCD_DELAY_DATA);
	LCD_RS_PORT&=~LCD_RS;        //RS=0
	lcd_trans(command);
}

/*向lcd发个数据*/
void lcd_send_data(unsigned char data)
{
	_delay_us(LCD_DELAY_DATA);
	LCD_RS_PORT|=LCD_RS;       //RS=1
	lcd_trans(data);
}

/*设置光标位置*/
void lcd_set_xy( unsigned char x, unsigned char y )
{
	unsigned char address;
	if (y == 0) address = 0x80 + x;
	else   address = 0xc0 + x;
	lcd_command( address);
}

/*写个字符*/
void inline lcd_putc(const char c){
	lcd_send_data(c);
}

/*写字串，\0 结尾*/
void lcd_puts(const char *s){
	while (*s)
	{
		lcd_putc( *s );
		s ++;
	}
}

/*向指定的位置写个字符*/
void inline lcd_posc(unsigned char X,unsigned char Y, char data)
{
	lcd_set_xy( X, Y );
	lcd_send_data( data);
}

/*向指定的位置写个字串*/
void inline lcd_poss(unsigned char X,unsigned char Y,const char *s)
{
	lcd_set_xy( X, Y );
	lcd_puts(s);
}

void lcd_clear( uint8_t row, uint8_t cow_st, uint8_t cow_ed )
{
	uint8_t i;
	lcd_set_xy( cow_st, row );
	for( i = cow_st; i < cow_ed; ++i ){
		lcd_putc( ' ' );
	}
}

#ifdef __PGMSPACE_H_
void lcd_puts_P( PGM_P s )
{
	char c;
	while( (c = pgm_read_byte_near(s)) != '\0' )
	{
		lcd_putc( c );
		s++;
	}
}
void lcd_poss_P( uint8_t x, uint8_t y, PGM_P s )
{
	lcd_set_xy( x, y );
	lcd_puts_P( s );
}
#endif


